<template>
  <div>
    <h1>音频通话</h1>

    <div>
      <audio style="display: none;" ref="localAudio" controls autoplay muted></audio>
      <audio style="display: none;" ref="remoteAudio" controls autoplay></audio>
    </div>

    <div>
      <p>你的 Peer ID: {{ peerId }}</p>
    </div>

    <div>
      <input v-model="remoteId" type="text" placeholder="请输入远程用户ID" />
      <button @click="callRemote" :disabled="caller">拨打音频通话</button>
      <button v-if="called" @click="acceptCalled">接受来电</button>
      <button @click="hangUp">挂断电话</button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import Peer from 'peerjs'

const localAudio = ref<HTMLAudioElement>()
const remoteAudio = ref<HTMLAudioElement>()
const peerId = ref<string>('')
const remoteId = ref<string>('')
const peer = ref<any>(null)
const caller = ref<boolean>(false)
const called = ref<boolean>(false)
const callObj = ref<any>(null)
let localStream: MediaStream | null = null

onMounted(() => {
  initPeer()
})

onUnmounted(() => {
  hangUp()
})

function initPeer() {
  const savedPeerId = localStorage.getItem('peerId')

  if (savedPeerId) {
    peer.value = new Peer(savedPeerId, {
      host: 'localhost',
      port: 3001,
      path: '/myPeerServer',
      debug: 3
    })

    peer.value.on('error', (err: any) => {
      console.error('Peer 错误:', err)
      if (err.type === 'unavailable-id') {
        console.log('Peer ID 无效，重新生成')
        createNewPeer()
      }
    })
  } else {
    createNewPeer()
  }

  peer.value.on('open', (id: string) => {
    console.log('Peer ID:', id)
    peerId.value = id
    localStorage.setItem('peerId', id)
  })

  peer.value.on('call', async (call: any) => {
    console.log('接收到通话邀请')
    called.value = true
    callObj.value = call
  })
}

function createNewPeer() {
  peer.value = new Peer({
    host: 'localhost',
    port: 3001,
    path: '/myPeerServer',
    debug: 3
  })

  peer.value.on('open', (id: string) => {
    peerId.value = id
    localStorage.setItem('peerId', id)
  })
}

async function getLocalStream(constraints: MediaStreamConstraints) {
  if (!localStream) {
    localStream = await navigator.mediaDevices.getUserMedia(constraints)
    localAudio.value!.srcObject = localStream
    localAudio.value!.play()
  }
  return localStream
}

const acceptCalled = async () => {
  const stream = await getLocalStream({ audio: true })
  callObj.value.answer(stream)
  callObj.value.on('stream', (remoteStream: any) => {
    console.log('接收到远程音频流')
    called.value = false
    remoteAudio.value!.srcObject = remoteStream
    setTimeout(() => {
      remoteAudio.value!.play().catch(err => console.log('播放失败:', err))
    }, 100)
  })
}

const callRemote = async () => {
  if (!remoteId.value) {
    alert('请输入对方ID')
    return
  }
  const stream = await getLocalStream({ audio: true })
  const call = peer.value.call(remoteId.value, stream)
  caller.value = true
  callObj.value = call
  call.on('stream', (remoteStream: any) => {
    console.log('接收到远程音频流')
    caller.value = false
    remoteAudio.value!.srcObject = remoteStream
    setTimeout(() => {
      remoteAudio.value!.play().catch(err => console.log('播放失败:', err))
    }, 100)
  })
}

const hangUp = () => {
  if (callObj.value) {
    callObj.value.close()
    callObj.value = null
  }

  if (peer.value) {
    peer.value.destroy()
    peer.value = null
  }

  if (localStream) {
    localStream.getTracks().forEach(track => track.stop())
    localStream = null
  }

  caller.value = false
  called.value = false
}
</script>

<style scoped>
audio {
  margin: 10px;
}

input {
  padding: 5px;
  margin-right: 10px;
}

button {
  padding: 10px;
  margin: 10px;
}
</style>
